/*********************************************************************************
 *
 *        SolarDrawCamera.java
 *
 *    Code for manipulating a camera
 *
 *********************************************************************************
 *    Copyright 2003 Brown University -- Steven P. Reiss
 *********************************************************************************
 *  Copyright 2003, Brown University, Providence, RI.
 *
 *              All Rights Reserved
 *
 *  Permission to use, copy, modify, and distribute this software and its
 *  documentation for any purpose other than its incorporation into a
 *  commercial product is hereby granted without fee, provided that the
 *  above copyright notice appear in all copies and that both that
 *  copyright notice and this permission notice appear in supporting
 *  documentation, and that the name of Brown University not be used in
 *  advertising or publicity pertaining to distribution of the software
 *  without specific, written prior permission.
 *
 *  BROWN UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
 *  SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 *  FITNESS FOR ANY PARTICULAR PURPOSE.  IN NO EVENT SHALL BROWN UNIVERSITY
 *  BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
 *  DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 *  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 *  ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 *  OF THIS SOFTWARE.
 *
 ********************************************************************************/
/* RCS: $Header$ */
/*********************************************************************************
 *
 * $Log$
 *
 ********************************************************************************/
package solardraw;
import javax.media.opengl.GL;
import javax.media.opengl.glu.GLU;
class SolarDrawCamera {
    /********************************************************************************
    /*
    /* Local storage
    /*
    /********************************************************************************/
    private SolarDrawVector look_at;
    private SolarDrawVector camera_at;
    private SolarDrawVector camera_up;
    private SolarDrawVector camera_right;
    private SolarDrawVector camera_in;
    private double aspect_ratio;
    private double cur_angle;
    private int window_width;
    private int window_height;
    private boolean do_perspective;
    private SolarDrawVector temp_v;
    private SolarDrawVector temp_v1;
    private static boolean do_print = false;
    private static double DEFAULT_ANGLE = 16.0;
    private static double MIN_ANGLE = 0.01;
    /********************************************************************************
    /*
    /* Constructors
    /*
    /********************************************************************************/
    SolarDrawCamera() {
        look_at = new SolarDrawVector();
        camera_at = new SolarDrawVector();
        camera_up = new SolarDrawVector();
        camera_right = new SolarDrawVector();
        camera_in = new SolarDrawVector();
        aspect_ratio = 0;
        cur_angle = 0;
        window_width = 0;
        window_height = 0;
        do_perspective = true;
        temp_v = new SolarDrawVector();
        temp_v1 = new SolarDrawVector();
        resetSettings();
    }
    /********************************************************************************
    /*
    /* Access methods
    /*
    /********************************************************************************/
    int getWindowWidth() {
        return window_width;
    }
    int getWindowHeight() {
        return window_height;
    }
    /********************************************************************************
    /*
    /* Window management methods
    /*
    /********************************************************************************/
    void setup(int w, int h) {
        window_width = w;
        window_height = h;
        aspect_ratio = ((double) w) / ((double) h);
        cur_angle = DEFAULT_ANGLE;
    }
    void resetSettings() {
        look_at.clear();
        camera_at.set(0, 0, 1e1);
        camera_up.set(0, 1, 0);
        camera_right.set(1, 0, 0);
        camera_in.set(0, 0, -1);
        cur_angle = DEFAULT_ANGLE;
        do_perspective = true;
    }
    /********************************************************************************
    /*
    /* Camera type methods
    /*
    /********************************************************************************/
    void toggleCameraType() {
        do_perspective = !do_perspective;
    }
    /********************************************************************************
    /*
    /* Panning methods
    /*
    /********************************************************************************/
    void panLeftRight(double d) {
        if (do_print) {
            System.err.println("CAMERA PANLR " + d);
        }
        d *= cur_angle / DEFAULT_ANGLE;
        look_at.linearOp(camera_right, -d);
        camera_at.linearOp(camera_right, -d);
    }
    void panUpDown(double d) {
        if (do_print) {
            System.err.println("CAMERA PANUD " + d);
        }
        d *= cur_angle / DEFAULT_ANGLE;
        look_at.linearOp(camera_up, -d);
        camera_at.linearOp(camera_up, d);
    }
    void panInOut(double d) {
        if (do_print) {
            System.err.println("CAMERA PANIO " + d);
        }
        camera_at.linearOp(camera_in, d);
    }
    /********************************************************************************
    /*
    /* Zooming methods
    /*
    /********************************************************************************/
    void zoomInOut(double d) {
        if (do_print) {
            System.err.println("CAMERA ZOOM " + d);
        }
        if (d == 0) {
            cur_angle = DEFAULT_ANGLE;
        } else {
            cur_angle += d;
        }
        if (cur_angle <= MIN_ANGLE) {
            cur_angle = MIN_ANGLE;
        }
    }
    /********************************************************************************
    *
    * Rotation methods
    *
    /********************************************************************************/
    void rotateUpDown(double deg) {
        if (do_print) {
            System.err.println("CAMERA UPDOWN " + deg);
        }
        doRotate(camera_right, deg);
    }
    void rotateLeftRight(double deg) {
        if (do_print) {
            System.err.println("CAMERA LEFTRIGHT " + deg);
        }
        doRotate(camera_up, deg);
    }
    private void doRotate(SolarDrawVector v, double deg) {
        SolarDrawMatrix m1 = new SolarDrawMatrix();
        SolarDrawMatrix m2 = new SolarDrawMatrix();
        m1.translate(look_at, -1);
        m2.rotateDeg(v, deg);
        m1.leftMult(m2);
        m2.translate(look_at, 1);
        m1.leftMult(m2);
        temp_v.copyFrom(camera_at);
        temp_v.leftMult(m1);
        adjust(camera_up, m1, temp_v);
        adjust(camera_right, m1, temp_v);
        adjust(camera_in, m1, temp_v);
        camera_at.copyFrom(temp_v);
    }
    private void adjust(SolarDrawVector v, SolarDrawMatrix m,
            SolarDrawVector nat) {
        temp_v1.copyFrom(camera_at);
        temp_v1.addTo(v);
        temp_v1.leftMult(m);
        temp_v1.subFrom(nat);
        temp_v1.normalize();
        v.copyFrom(temp_v1);
    }
    /********************************************************************************
    *
    * Drawing methods
    *
    /********************************************************************************/
    void draw(GL gl, GLU glu) {
        if (do_print) {
            System.err.println("VIEWPORT " + window_width + " x "
                    + window_height);
            System.err.println("CAMERA " + camera_at.getX() + " "
                    + camera_at.getY() + " " + camera_at.getZ());
            System.err.println("LOOK " + look_at.getX() + " " + look_at.getY()
                    + " " + look_at.getZ());
            System.err.println("UP " + camera_up.getX() + " "
                    + camera_up.getY() + " " + camera_up.getZ());
            System.err.println("PROJECT " + cur_angle + " " + aspect_ratio);
        }
        gl.glViewport(0, 0, window_width, window_height);
        glu.gluLookAt(camera_at.getX(), camera_at.getY(), camera_at.getZ(),
                look_at.getX(), look_at.getY(), look_at.getZ(), camera_up.getX(), camera_up.getY(), camera_up.getZ());
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        if (do_perspective) {
            glu.gluPerspective(cur_angle, aspect_ratio, 1.0, 100.0);
        } else {
            double v = cur_angle / DEFAULT_ANGLE / 2;
            gl.glOrtho(-v, v, -v, v, -10, 10);
        }
        gl.glMatrixMode(GL.GL_MODELVIEW);
    }
} // end of SolarDrawCamera

